home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / MAKE / SUFF.C < prev    next >
C/C++ Source or Header  |  1992-06-29  |  61KB  |  2,160 lines

  1. /*
  2.  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
  3.  * Copyright (c) 1988, 1989 by Adam de Boor
  4.  * Copyright (c) 1989 by Berkeley Softworks
  5.  * All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Adam de Boor.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *    This product includes software developed by the University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #ifndef lint
  40. static char sccsid[] = "@(#)suff.c    5.6 (Berkeley) 6/1/90";
  41. #endif /* not lint */
  42.  
  43. /*-
  44.  * suff.c --
  45.  *    Functions to maintain suffix lists and find implicit dependents
  46.  *    using suffix transformation rules
  47.  *
  48.  * Interface:
  49.  *    Suff_Init             Initialize all things to do with suffixes.
  50.  *
  51.  *    Suff_DoPaths            This function is used to make life easier
  52.  *                          when searching for a file according to its
  53.  *                          suffix. It takes the global search path,
  54.  *                          as defined using the .PATH: target, and appends
  55.  *                          its directories to the path of each of the
  56.  *                          defined suffixes, as specified using
  57.  *                          .PATH<suffix>: targets. In addition, all
  58.  *                          directories given for suffixes labeled as
  59.  *                          include files or libraries, using the .INCLUDES
  60.  *                          or .LIBS targets, are played with using
  61.  *                          Dir_MakeFlags to create the .INCLUDES and
  62.  *                          .LIBS global variables.
  63.  *
  64.  *    Suff_ClearSuffixes      Clear out all the suffixes and defined
  65.  *                          transformations.
  66.  *
  67.  *    Suff_IsTransform        Return TRUE if the passed string is the lhs
  68.  *                          of a transformation rule.
  69.  *
  70.  *    Suff_AddSuffix            Add the passed string as another known suffix.
  71.  *
  72.  *    Suff_GetPath            Return the search path for the given suffix.
  73.  *
  74.  *    Suff_AddInclude            Mark the given suffix as denoting an include
  75.  *                          file.
  76.  *
  77.  *    Suff_AddLib            Mark the given suffix as denoting a library.
  78.  *
  79.  *    Suff_AddTransform       Add another transformation to the suffix
  80.  *                          graph. Returns  GNode suitable for framing, I
  81.  *                          mean, tacking commands, attributes, etc. on.
  82.  *
  83.  *    Suff_SetNull            Define the suffix to consider the suffix of
  84.  *                          any file that doesn't have a known one.
  85.  *
  86.  *    Suff_FindDeps            Find implicit sources for and the location of
  87.  *                          a target based on its suffix. Returns the
  88.  *                          bottom-most node added to the graph or NILGNODE
  89.  *                          if the target had no implicit sources.
  90.  */
  91.  
  92. #include          <stdio.h>
  93. #include      "make.h"
  94. #include          "bit.h"
  95.  
  96. static Lst       sufflist;    /* Lst of suffixes */
  97. static Lst       transforms;    /* Lst of transformation rules */
  98.  
  99. static int        sNum = 0;    /* Counter for assigning suffix numbers */
  100.  
  101. /*
  102.  * Structure describing an individual suffix.
  103.  */
  104. typedef struct _Suff {
  105.     char         *name;            /* The suffix itself */
  106.     int         nameLen;    /* Length of the suffix */
  107.     short     flags;          /* Type of suffix */
  108. #define SUFF_INCLUDE      0x01        /* One which is #include'd */
  109. #define SUFF_LIBRARY      0x02        /* One which contains a library */
  110. #define SUFF_NULL       0x04        /* The empty suffix */
  111.     Lst         searchPath;    /* The path along which files of this suffix
  112.                  * may be found */
  113.     int          sNum;              /* The suffix number */
  114.     Lst          parents;    /* Suffixes we have a transformation to */
  115.     Lst          children;    /* Suffixes we have a transformation from */
  116. } Suff;
  117.  
  118. /*
  119.  * Structure used in the search for implied sources.
  120.  */
  121. typedef struct _Src {
  122.     char            *file;    /* The file to look for */
  123.     char            *pref;      /* Prefix from which file was formed */
  124.     Suff            *suff;    /* The suffix on the file */
  125.     struct _Src     *parent;    /* The Src for which this is a source */
  126.     GNode           *node;    /* The node describing the file */
  127.     int                children;    /* Count of existing children (so we don't free
  128.                  * this thing too early or never nuke it) */
  129. } Src;
  130.  
  131. static Suff         *suffNull;    /* The NULL suffix for this run */
  132. static Suff         *emptySuff;    /* The empty suffix required for POSIX
  133.                  * single-suffix transformation rules */
  134.  
  135.     /*************** Lst Predicates ****************/
  136. /*-
  137.  *-----------------------------------------------------------------------
  138.  * SuffStrIsPrefix  --
  139.  *    See if pref is a prefix of str.
  140.  *
  141.  * Results:
  142.  *    NULL if it ain't, pointer to character in str after prefix if so
  143.  *
  144.  * Side Effects:
  145.  *    None
  146.  *-----------------------------------------------------------------------
  147.  */
  148. static char    *
  149. SuffStrIsPrefix (pref, str)
  150.     register char  *pref;    /* possible prefix */
  151.     register char  *str;    /* string to check */
  152. {
  153.     while (*str && *pref == *str) {
  154.     pref++;
  155.     str++;
  156.     }
  157.  
  158.     return (*pref ? NULL : str);
  159. }
  160.  
  161. /*-
  162.  *-----------------------------------------------------------------------
  163.  * SuffSuffIsSuffix  --
  164.  *    See if suff is a suffix of str. Str should point to THE END of the
  165.  *    string to check. (THE END == the null byte)
  166.  *
  167.  * Results:
  168.  *    NULL if it ain't, pointer to character in str before suffix if
  169.  *    it is.
  170.  *
  171.  * Side Effects:
  172.  *    None
  173.  *-----------------------------------------------------------------------
  174.  */
  175. static char *
  176. SuffSuffIsSuffix (s, str)
  177.     register Suff  *s;        /* possible suffix */
  178.     char           *str;    /* string to examine */
  179. {
  180.     register char  *p1;            /* Pointer into suffix name */
  181.     register char  *p2;            /* Pointer into string being examined */
  182.  
  183.     p1 = s->name + s->nameLen;
  184.     p2 = str;
  185.  
  186.     while (p1 >= s->name && *p1 == *p2) {
  187.     p1--;
  188.     p2--;
  189.     }
  190.  
  191.     return (p1 == s->name - 1 ? p2 : NULL);
  192. }
  193.  
  194. /*-
  195.  *-----------------------------------------------------------------------
  196.  * SuffSuffIsSuffixP --
  197.  *    Predicate form of SuffSuffIsSuffix. Passed as the callback function
  198.  *    to Lst_Find.
  199.  *
  200.  * Results:
  201.  *    0 if the suffix is the one desired, non-zero if not.
  202.  *
  203.  * Side Effects:
  204.  *    None.
  205.  *
  206.  *-----------------------------------------------------------------------
  207.  */
  208. SuffSuffIsSuffixP(s, str)
  209.     Suff        *s;
  210.     char        *str;
  211. {
  212.     return(!SuffSuffIsSuffix(s, str));
  213. }
  214.  
  215. /*-
  216.  *-----------------------------------------------------------------------
  217.  * SuffSuffHasNameP --
  218.  *    Callback procedure for finding a suffix based on its name. Used by
  219.  *    Suff_GetPath.
  220.  *
  221.  * Results:
  222.  *    0 if the suffix is of the given name. non-zero otherwise.
  223.  *
  224.  * Side Effects:
  225.  *    None
  226.  *-----------------------------------------------------------------------
  227.  */
  228. static int
  229. SuffSuffHasNameP (s, sname)
  230.     Suff    *s;                /* Suffix to check */
  231.     char    *sname;         /* Desired name */
  232. {
  233.     return (strcmp (sname, s->name));
  234. }
  235.  
  236. /*-
  237.  *-----------------------------------------------------------------------
  238.  * SuffSuffIsPrefix  --
  239.  *    See if the suffix described by s is a prefix of the string. Care
  240.  *    must be taken when using this to search for transformations and
  241.  *    what-not, since there could well be two suffixes, one of which
  242.  *    is a prefix of the other...
  243.  *
  244.  * Results:
  245.  *    0 if s is a prefix of str. non-zero otherwise
  246.  *
  247.  * Side Effects:
  248.  *    None
  249.  *-----------------------------------------------------------------------
  250.  */
  251. static int
  252. SuffSuffIsPrefix (s, str)
  253.     Suff           *s;        /* suffix to compare */
  254.     char           *str;    /* string to examine */
  255. {
  256.     return (SuffStrIsPrefix (s->name, str) == NULL ? 1 : 0);
  257. }
  258.  
  259. /*-
  260.  *-----------------------------------------------------------------------
  261.  * SuffGNHasNameP  --
  262.  *    See if the graph node has the desired name
  263.  *
  264.  * Results:
  265.  *    0 if it does. non-zero if it doesn't
  266.  *
  267.  * Side Effects:
  268.  *    None
  269.  *-----------------------------------------------------------------------
  270.  */
  271. static int
  272. SuffGNHasNameP (gn, name)
  273.     GNode          *gn;        /* current node we're looking at */
  274.     char           *name;    /* name we're looking for */
  275. {
  276.     return (strcmp (name, gn->name));
  277. }
  278.  
  279.          /*********** Maintenance Functions ************/
  280. /*-
  281.  *-----------------------------------------------------------------------
  282.  * SuffFree  --
  283.  *    Free up all memory associated with the given suffix structure.
  284.  *
  285.  * Results:
  286.  *    none
  287.  *
  288.  * Side Effects:
  289.  *    the suffix entry is detroyed
  290.  *-----------------------------------------------------------------------
  291.  */
  292. static void
  293. SuffFree (s)
  294.     Suff           *s;
  295. {
  296.     Lst_Destroy (s->children, NOFREE);
  297.     Lst_Destroy (s->parents, NOFREE);
  298.     Lst_Destroy (s->searchPath, Dir_Destroy);
  299.     free ((Address)s->name);
  300.     free ((Address)s);
  301. }
  302.  
  303. /*-
  304.  *-----------------------------------------------------------------------
  305.  * SuffInsert  --
  306.  *    Insert the suffix into the list keeping the list ordered by suffix
  307.  *    numbers.
  308.  *
  309.  * Results:
  310.  *    None
  311.  *
  312.  * Side Effects:
  313.  *    Not really
  314.  *-----------------------------------------------------------------------
  315.  */
  316. static void
  317. SuffInsert (l, s)
  318.     Lst           l;        /* the list where in s should be inserted */
  319.     Suff          *s;        /* the suffix to insert */
  320. {
  321.     LstNode       ln;        /* current element in l we're examining */
  322.     Suff          *s2;        /* the suffix descriptor in this element */
  323.  
  324.     if (Lst_Open (l) == FAILURE) {
  325.     return;
  326.     }
  327.     while ((ln = Lst_Next (l)) != NILLNODE) {
  328.     s2 = (Suff *) Lst_Datum (ln);
  329.     if (s2->sNum >= s->sNum) {
  330.         break;
  331.     }
  332.     }
  333.  
  334.     Lst_Close (l);
  335.     if (DEBUG(SUFF)) {
  336.     printf("inserting %s(%d)...", s->name, s->sNum);
  337.     }
  338.     if (ln == NILLNODE) {
  339.     if (DEBUG(SUFF)) {
  340.         printf("at end of list\n");
  341.     }
  342.     (void)Lst_AtEnd (l, (ClientData)s);
  343.     } else if (s2->sNum != s->sNum) {
  344.     if (DEBUG(SUFF)) {
  345.         printf("before %s(%d)\n", s2->name, s2->sNum);
  346.     }
  347.     (void)Lst_Insert (l, ln, (ClientData)s);
  348.     } else if (DEBUG(SUFF)) {
  349.     printf("already there\n");
  350.     }
  351. }
  352.  
  353. /*-
  354.  *-----------------------------------------------------------------------
  355.  * Suff_ClearSuffixes --
  356.  *    This is gross. Nuke the list of suffixes but keep all transformation
  357.  *    rules around. The transformation graph is destroyed in this process,
  358.  *    but we leave the list of rules so when a new graph is formed the rules
  359.  *    will remain.
  360.  *    This function is called from the parse module when a
  361.  *    .SUFFIXES:\n line is encountered.
  362.  *
  363.  * Results:
  364.  *    none
  365.  *
  366.  * Side Effects:
  367.  *    the sufflist and its graph nodes are destroyed
  368.  *-----------------------------------------------------------------------
  369.  */
  370. void
  371. Suff_ClearSuffixes ()
  372. {
  373.     Lst_Destroy (sufflist, SuffFree);
  374.  
  375.     sufflist = Lst_Init(FALSE);
  376.     sNum = 0;
  377.     suffNull = emptySuff;
  378. }
  379.  
  380. /*-
  381.  *-----------------------------------------------------------------------
  382.  * SuffParseTransform --
  383.  *    Parse a transformation string to find its two component suffixes.
  384.  *
  385.  * Results:
  386.  *    TRUE if the string is a valid transformation and FALSE otherwise.
  387.  *
  388.  * Side Effects:
  389.  *    The passed pointers are overwritten.
  390.  *
  391.  *-----------------------------------------------------------------------
  392.  */
  393. static Boolean
  394. SuffParseTransform(str, srcPtr, targPtr)
  395.     char              *str;            /* String being parsed */
  396.     Suff              **srcPtr;       /* Place to store source of trans. */
  397.     Suff              **targPtr;      /* Place to store target of trans. */
  398. {
  399.     register LstNode    srcLn;        /* element in suffix list of trans source*/
  400.     register Suff        *src;        /* Source of transformation */
  401.     register LstNode    targLn;        /* element in suffix list of trans target*/
  402.     register char        *str2;        /* Extra pointer (maybe target suffix) */
  403.     LstNode             singleLn;   /* element in suffix list of any suffix
  404.                      * that exactly matches str */
  405.     Suff                *single;    /* Source of possible transformation to
  406.                      * null suffix */
  407.  
  408.     srcLn = NILLNODE;
  409.     singleLn = NILLNODE;
  410.     
  411.     /*
  412.      * Loop looking first for a suffix that matches the start of the
  413.      * string and then for one that exactly matches the rest of it. If
  414.      * we can find two that meet these criteria, we've successfully
  415.      * parsed the string.
  416.      */
  417.     while (1) {
  418.     if (srcLn == NILLNODE) {
  419.         srcLn = Lst_Find(sufflist, (ClientData)str, SuffSuffIsPrefix);
  420.     } else {
  421.         srcLn = Lst_FindFrom (sufflist, Lst_Succ(srcLn), (ClientData)str,
  422.                   SuffSuffIsPrefix);
  423.     }
  424.     if (srcLn == NILLNODE) {
  425.         /*
  426.          * Ran out of source suffixes -- no such rule
  427.          */
  428.         if (singleLn != NILLNODE) {
  429.         /*
  430.          * Not so fast Mr. Smith! There was a suffix that encompassed
  431.          * the entire string, so we assume it was a transformation
  432.          * to the null suffix (thank you POSIX). We still prefer to
  433.          * find a double rule over a singleton, hence we leave this
  434.          * check until the end.
  435.          *
  436.          * XXX: Use emptySuff over suffNull?
  437.          */
  438.         *srcPtr = single;
  439.         *targPtr = suffNull;
  440.         return(TRUE);
  441.         }
  442.         return (FALSE);
  443.     }
  444.     src = (Suff *) Lst_Datum (srcLn);
  445.     str2 = str + src->nameLen;
  446.     if (*str2 == '\0') {
  447.         single = src;
  448.         singleLn = srcLn;
  449.     } else {
  450.         targLn = Lst_Find(sufflist, (ClientData)str2, SuffSuffHasNameP);
  451.         if (targLn != NILLNODE) {
  452.         *srcPtr = src;
  453.         *targPtr = (Suff *)Lst_Datum(targLn);
  454.         return (TRUE);
  455.         }
  456.     }
  457.     }
  458. }
  459.  
  460. /*-
  461.  *-----------------------------------------------------------------------
  462.  * Suff_IsTransform  --
  463.  *    Return TRUE if the given string is a transformation rule
  464.  *
  465.  *
  466.  * Results:
  467.  *    TRUE if the string is a concatenation of two known suffixes.
  468.  *    FALSE otherwise
  469.  *
  470.  * Side Effects:
  471.  *    None
  472.  *-----------------------------------------------------------------------
  473.  */
  474. Boolean
  475. Suff_IsTransform (str)
  476.     char          *str;            /* string to check */
  477. {
  478.     Suff          *src, *targ;
  479.  
  480.     return (SuffParseTransform(str, &src, &targ));
  481. }
  482.  
  483. /*-
  484.  *-----------------------------------------------------------------------
  485.  * Suff_AddTransform --
  486.  *    Add the transformation rule described by the line to the
  487.  *    list of rules and place the transformation itself in the graph
  488.  *
  489.  * Results:
  490.  *    The node created for the transformation in the transforms list
  491.  *
  492.  * Side Effects:
  493.  *    The node is placed on the end of the transforms Lst and links are
  494.  *    made between the two suffixes mentioned in the target name
  495.  *-----------------------------------------------------------------------
  496.  */
  497. GNode *
  498. Suff_AddTransform (line)
  499.     char          *line;    /* name of transformation to add */
  500. {
  501.     GNode         *gn;        /* GNode of transformation rule */
  502.     Suff          *s,        /* source suffix */
  503.                   *t;        /* target suffix */
  504.     LstNode       ln;            /* Node for existing transformation */
  505.  
  506.     ln = Lst_Find (transforms, (ClientData)line, SuffGNHasNameP);
  507.     if (ln == NILLNODE) {
  508.     /*
  509.      * Make a new graph node for the transformation. It will be filled in
  510.      * by the Parse module. 
  511.      */
  512.     gn = Targ_NewGN (line);
  513.     (void)Lst_AtEnd (transforms, (ClientData)gn);
  514.     } else {
  515.     /*
  516.      * New specification for transformation rule. Just nuke the old list
  517.      * of commands so they can be filled in again... We don't actually
  518.      * free the commands themselves, because a given command can be
  519.      * attached to several different transformations.
  520.      */
  521.     gn = (GNode *) Lst_Datum (ln);
  522.     Lst_Destroy (gn->commands, NOFREE);
  523.     Lst_Destroy (gn->children, NOFREE);
  524.     gn->commands = Lst_Init (FALSE);
  525.     gn->children = Lst_Init (FALSE);
  526.     }
  527.  
  528.     gn->type = OP_TRANSFORM;
  529.  
  530.     (void)SuffParseTransform(line, &s, &t);
  531.  
  532.     /*
  533.      * link the two together in the proper relationship and order 
  534.      */
  535.     if (DEBUG(SUFF)) {
  536.     printf("defining transformation from `%s' to `%s'\n",
  537.         s->name, t->name);
  538.     }
  539.     SuffInsert (t->children, s);
  540.     SuffInsert (s->parents, t);
  541.  
  542.     return (gn);
  543. }
  544.  
  545. /*-
  546.  *-----------------------------------------------------------------------
  547.  * Suff_EndTransform --
  548.  *    Handle the finish of a transformation definition, removing the
  549.  *    transformation from the graph if it has neither commands nor
  550.  *    sources. This is a callback procedure for the Parse module via
  551.  *    Lst_ForEach
  552.  *
  553.  * Results:
  554.  *    === 0
  555.  *
  556.  * Side Effects:
  557.  *    If the node has no commands or children, the children and parents
  558.  *    lists of the affected suffices are altered.
  559.  *
  560.  *-----------------------------------------------------------------------
  561.  */
  562. int
  563. Suff_EndTransform(gn)
  564.     GNode   *gn;        /* Node for transformation */
  565. {
  566.     if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(gn->commands) &&
  567.     Lst_IsEmpty(gn->children))
  568.     {
  569.     Suff    *s, *t;
  570.     LstNode    ln;
  571.  
  572.     (void)SuffParseTransform(gn->name, &s, &t);
  573.  
  574.     if (DEBUG(SUFF)) {
  575.         printf("deleting transformation from %s to %s\n",
  576.             s->name, t->name);
  577.     }
  578.  
  579.     /*
  580.      * Remove the source from the target's children list. We check for a
  581.      * nil return to handle a beanhead saying something like
  582.      *  .c.o .c.o:
  583.      *
  584.      * We'll be called twice when the next target is seen, but .c and .o
  585.      * are only linked once...
  586.      */
  587.     ln = Lst_Member(t->children, (ClientData)s);
  588.     if (ln != NILLNODE) {
  589.         (void)Lst_Remove(t->children, ln);
  590.     }
  591.  
  592.     /*
  593.      * Remove the target from the source's parents list
  594.      */
  595.     ln = Lst_Member(s->parents, (ClientData)t);
  596.     if (ln != NILLNODE) {
  597.         (void)Lst_Remove(s->parents, ln);
  598.     }
  599.     } else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) {
  600.     printf("transformation %s complete\n", gn->name);
  601.     }
  602.  
  603.     return(0);
  604. }
  605.  
  606. /*-
  607.  *-----------------------------------------------------------------------
  608.  * SuffRebuildGraph --
  609.  *    Called from Suff_AddSuffix via Lst_ForEach to search through the
  610.  *    list of existing transformation rules and rebuild the transformation
  611.  *    graph when it has been destroyed by Suff_ClearSuffixes. If the
  612.  *    given rule is a transformation involving this suffix and another,
  613.  *    existing suffix, the proper relationship is established between
  614.  *    the two.
  615.  *
  616.  * Results:
  617.  *    Always 0.
  618.  *
  619.  * Side Effects:
  620.  *    The appropriate links will be made between this suffix and
  621.  *    others if transformation rules exist for it.
  622.  *
  623.  *-----------------------------------------------------------------------
  624.  */
  625. static int
  626. SuffRebuildGraph(transform, s)
  627.     GNode             *transform; /* Transformation to test */
  628.     Suff              *s;        /* Suffix to rebuild */
  629. {
  630.     register char     *cp;
  631.     register LstNode    ln;
  632.     register Suff      *s2;
  633.  
  634.     /*
  635.      * First see if it is a transformation from this suffix.
  636.      */
  637.     cp = SuffStrIsPrefix(s->name, transform->name);
  638.     if (cp != (char *)NULL) {
  639.     ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffHasNameP);
  640.     if (ln != NILLNODE) {
  641.         /*
  642.          * Found target. Link in and return, since it can't be anything
  643.          * else.
  644.          */
  645.         s2 = (Suff *)Lst_Datum(ln);
  646.         SuffInsert(s2->children, s);
  647.         SuffInsert(s->parents, s2);
  648.         return(0);
  649.     }
  650.     }
  651.  
  652.     /*
  653.      * Not from, maybe to?
  654.      */
  655.     cp = SuffSuffIsSuffix(s, transform->name + strlen(transform->name));
  656.     if (cp != (char *)NULL) {
  657.     /*
  658.      * Null-terminate the source suffix in order to find it.
  659.      */
  660.     cp[1] = '\0';
  661.     ln = Lst_Find(sufflist, (ClientData)transform->name, SuffSuffHasNameP);
  662.     /*
  663.      * Replace the start of the target suffix
  664.      */
  665.     cp[1] = s->name[0];
  666.     if (ln != NILLNODE) {
  667.         /*
  668.          * Found it -- establish the proper relationship
  669.          */
  670.         s2 = (Suff *)Lst_Datum(ln);
  671.         SuffInsert(s->children, s2);
  672.         SuffInsert(s2->parents, s);
  673.     }
  674.     }
  675.     return(0);
  676. }
  677.  
  678. /*-
  679.  *-----------------------------------------------------------------------
  680.  * Suff_AddSuffix --
  681.  *    Add the suffix in string to the end of the list of known suffixes.
  682.  *    Should we restructure the suffix graph? Make doesn't...
  683.  *
  684.  * Results:
  685.  *    None
  686.  *
  687.  * Side Effects:
  688.  *    A GNode is created for the suffix and a Suff structure is created and
  689.  *    added to the suffixes list unless the suffix was already known.
  690.  *-----------------------------------------------------------------------
  691.  */
  692. void
  693. Suff_AddSuffix (str)
  694.     char          *str;        /* the name of the suffix to add */
  695. {
  696.     Suff          *s;        /* new suffix descriptor */
  697.     LstNode       ln;
  698.  
  699.     ln = Lst_Find (sufflist, (ClientData)str, SuffSuffHasNameP);
  700.     if (ln == NILLNODE) {
  701.     s = (Suff *) emalloc (sizeof (Suff));
  702.  
  703.     s->name =       strdup (str);
  704.     s->nameLen =     strlen (s->name);
  705.     s->searchPath = Lst_Init (FALSE);
  706.     s->children =     Lst_Init (FALSE);
  707.     s->parents =     Lst_Init (FALSE);
  708.     s->sNum =       sNum++;
  709.     s->flags =      0;
  710.  
  711.     (void)Lst_AtEnd (sufflist, (ClientData)s);
  712.     /*
  713.      * Look for any existing transformations from or to this suffix.
  714.      * XXX: Only do this after a Suff_ClearSuffixes?
  715.      */
  716.     Lst_ForEach (transforms, SuffRebuildGraph, (ClientData)s);
  717.     } 
  718. }
  719.  
  720. /*-
  721.  *-----------------------------------------------------------------------
  722.  * Suff_GetPath --
  723.  *    Return the search path for the given suffix, if it's defined.
  724.  *
  725.  * Results:
  726.  *    The searchPath for the desired suffix or NILLST if the suffix isn't
  727.  *    defined.
  728.  *
  729.  * Side Effects:
  730.  *    None
  731.  *-----------------------------------------------------------------------
  732.  */
  733. Lst
  734. Suff_GetPath (sname)
  735.     char          *sname;
  736. {
  737.     LstNode         ln;
  738.     Suff          *s;
  739.  
  740.     ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP);
  741.     if (ln == NILLNODE) {
  742.     return (NILLST);
  743.     } else {
  744.     s = (Suff *) Lst_Datum (ln);
  745.     return (s->searchPath);
  746.     }
  747. }
  748.  
  749. /*-
  750.  *-----------------------------------------------------------------------
  751.  * Suff_DoPaths --
  752.  *    Extend the search paths for all suffixes to include the default
  753.  *    search path.
  754.  *
  755.  * Results:
  756.  *    None.
  757.  *
  758.  * Side Effects:
  759.  *    The searchPath field of all the suffixes is extended by the
  760.  *    directories in dirSearchPath. If paths were specified for the
  761.  *    ".h" suffix, the directories are stuffed into a global variable
  762.  *    called ".INCLUDES" with each directory preceeded by a -I. The same
  763.  *    is done for the ".a" suffix, except the variable is called
  764.  *    ".LIBS" and the flag is -L.
  765.  *-----------------------------------------------------------------------
  766.  */
  767. void
  768. Suff_DoPaths()
  769. {
  770.     register Suff       *s;
  771.     register LstNode      ln;
  772.     Lst                    inIncludes; /* Cumulative .INCLUDES path */
  773.     Lst                    inLibs;        /* Cumulative .LIBS path */
  774.  
  775.     if (Lst_Open (sufflist) == FAILURE) {
  776.     return;
  777.     }
  778.  
  779.     inIncludes = Lst_Init(FALSE);
  780.     inLibs = Lst_Init(FALSE);
  781.  
  782.     while ((ln = Lst_Next (sufflist)) != NILLNODE) {
  783.     s = (Suff *) Lst_Datum (ln);
  784.     if (!Lst_IsEmpty (s->searchPath)) {
  785. #ifdef INCLUDES
  786.         if (s->flags & SUFF_INCLUDE) {
  787.         Dir_Concat(inIncludes, s->searchPath);
  788.         }
  789. #endif /* INCLUDES */
  790. #ifdef LIBRARIES
  791.         if (s->flags & SUFF_LIBRARY) {
  792.         Dir_Concat(inLibs, s->searchPath);
  793.         }
  794. #endif /* LIBRARIES */
  795.         Dir_Concat(s->searchPath, dirSearchPath);
  796.     } else {
  797.         Lst_Destroy (s->searchPath, Dir_Destroy);
  798.         s->searchPath = Lst_Duplicate(dirSearchPath, Dir_CopyDir);
  799.     }
  800.     }
  801.  
  802.     Var_Set(".INCLUDES", Dir_MakeFlags("-I", inIncludes), VAR_GLOBAL);
  803.     Var_Set(".LIBS", Dir_MakeFlags("-L", inLibs), VAR_GLOBAL);
  804.  
  805.     Lst_Destroy(inIncludes, Dir_Destroy);
  806.     Lst_Destroy(inLibs, Dir_Destroy);
  807.  
  808.     Lst_Close (sufflist);
  809. }
  810.  
  811. /*-
  812.  *-----------------------------------------------------------------------
  813.  * Suff_AddInclude --
  814.  *    Add the given suffix as a type of file which gets included.
  815.  *    Called from the parse module when a .INCLUDES line is parsed.
  816.  *    The suffix must have already been defined.
  817.  *
  818.  * Results:
  819.  *    None.
  820.  *
  821.  * Side Effects:
  822.  *    The SUFF_INCLUDE bit is set in the suffix's flags field
  823.  *
  824.  *-----------------------------------------------------------------------
  825.  */
  826. void
  827. Suff_AddInclude (sname)
  828.     char      *sname;     /* Name of suffix to mark */
  829. {
  830.     LstNode      ln;
  831.     Suff      *s;
  832.  
  833.     ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP);
  834.     if (ln != NILLNODE) {
  835.     s = (Suff *) Lst_Datum (ln);
  836.     s->flags |= SUFF_INCLUDE;
  837.     }
  838. }
  839.  
  840. /*-
  841.  *-----------------------------------------------------------------------
  842.  * Suff_AddLib --
  843.  *    Add the given suffix as a type of file which is a library.
  844.  *    Called from the parse module when parsing a .LIBS line. The
  845.  *    suffix must have been defined via .SUFFIXES before this is
  846.  *    called.
  847.  *
  848.  * Results:
  849.  *    None.
  850.  *
  851.  * Side Effects:
  852.  *    The SUFF_LIBRARY bit is set in the suffix's flags field
  853.  *
  854.  *-----------------------------------------------------------------------
  855.  */
  856. void
  857. Suff_AddLib (sname)
  858.     char      *sname;     /* Name of suffix to mark */
  859. {
  860.     LstNode      ln;
  861.     Suff      *s;
  862.  
  863.     ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP);
  864.     if (ln != NILLNODE) {
  865.     s = (Suff *) Lst_Datum (ln);
  866.     s->flags |= SUFF_LIBRARY;
  867.     }
  868. }
  869.  
  870.        /********** Implicit Source Search Functions *********/
  871. /*
  872.  * A structure for passing more than one argument to the Lst-library-invoked
  873.  * function...
  874.  */
  875. typedef struct {
  876.     Lst            l;
  877.     Src            *s;
  878. } LstSrc;
  879.  
  880. /*-
  881.  *-----------------------------------------------------------------------
  882.  * SuffAddSrc  --
  883.  *    Add a suffix as a Src structure to the given list with its parent
  884.  *    being the given Src structure. If the suffix is the null suffix,
  885.  *    the prefix is used unaltered as the file name in the Src structure.
  886.  *
  887.  * Results:
  888.  *    always returns 0
  889.  *
  890.  * Side Effects:
  891.  *    A Src structure is created and tacked onto the end of the list
  892.  *-----------------------------------------------------------------------
  893.  */
  894. static int
  895. SuffAddSrc (s, ls)
  896.     Suff    *s;        /* suffix for which to create a Src structure */
  897.     LstSrc      *ls;        /* list and parent for the new Src */
  898. {
  899.     Src         *s2;        /* new Src structure */
  900.     Src        *targ;         /* Target structure */
  901.  
  902.     targ = ls->s;
  903.     
  904.     if ((s->flags & SUFF_NULL) && (*s->name != '\0')) {
  905.     /*
  906.      * If the suffix has been marked as the NULL suffix, also create a Src
  907.      * structure for a file with no suffix attached. Two birds, and all
  908.      * that...
  909.      */
  910.     s2 = (Src *) emalloc (sizeof (Src));
  911.     s2->file =      strdup(targ->pref);
  912.     s2->pref =      targ->pref;
  913.     s2->parent =     targ;
  914.     s2->node =      NILGNODE;
  915.     s2->suff =      s;
  916.     s2->children =    0;
  917.     targ->children += 1;
  918.     (void)Lst_AtEnd (ls->l, (ClientData)s2);
  919.     }
  920.     s2 = (Src *) emalloc (sizeof (Src));
  921.     s2->file =         str_concat (targ->pref, s->name, 0);
  922.     s2->pref =        targ->pref;
  923.     s2->parent =    targ;
  924.     s2->node =         NILGNODE;
  925.     s2->suff =         s;
  926.     s2->children =  0;
  927.     targ->children += 1;
  928.     (void)Lst_AtEnd (ls->l, (ClientData)s2);
  929.  
  930.     return(0);
  931. }
  932.  
  933. /*-
  934.  *-----------------------------------------------------------------------
  935.  * SuffAddLevel  --
  936.  *    Add all the children of targ as Src structures to the given list
  937.  *
  938.  * Results:
  939.  *    None
  940.  *
  941.  * Side Effects:
  942.  *     Lots of structures are created and added to the list
  943.  *-----------------------------------------------------------------------
  944.  */
  945. static void
  946. SuffAddLevel (l, targ)
  947.     Lst            l;        /* list to which to add the new level */
  948.     Src            *targ;    /* Src structure to use as the parent */
  949. {
  950.     LstSrc         ls;
  951.  
  952.     ls.s = targ;
  953.     ls.l = l;
  954.  
  955.     Lst_ForEach (targ->suff->children, SuffAddSrc, (ClientData)&ls);
  956. }
  957.  
  958. /*-
  959.  *----------------------------------------------------------------------
  960.  * SuffFreeSrc --
  961.  *    Free all memory associated with a Src structure
  962.  *
  963.  * Results:
  964.  *    None
  965.  *
  966.  * Side Effects:
  967.  *    The memory is free'd.
  968.  *----------------------------------------------------------------------
  969.  */
  970. static void
  971. SuffFreeSrc (s)
  972.     Src            *s;
  973. {
  974.     free ((Address)s->file);
  975.     if (!s->parent) {
  976.     free((Address)s->pref);
  977.     } else if (--s->parent->children == 0 && s->parent->parent) {
  978.     /*
  979.      * Parent has no more children, now we're gone, and it's not
  980.      * at the top of the tree, so blow it away too.
  981.      */
  982.     SuffFreeSrc(s->parent);
  983.     }
  984.     free ((Address)s);
  985. }
  986.  
  987. /*-
  988.  *-----------------------------------------------------------------------
  989.  * SuffFindThem --
  990.  *    Find the first existing file/target in the list srcs
  991.  *
  992.  * Results:
  993.  *    The lowest structure in the chain of transformations
  994.  *
  995.  * Side Effects:
  996.  *    None
  997.  *-----------------------------------------------------------------------
  998.  */
  999. static Src *
  1000. SuffFindThem (srcs)
  1001.     Lst            srcs;    /* list of Src structures to search through */
  1002. {
  1003.     Src            *s;        /* current Src */
  1004.     Src           *rs;        /* returned Src */
  1005.  
  1006.     rs = (Src *) NULL;
  1007.  
  1008.     while (!Lst_IsEmpty (srcs)) {
  1009.     s = (Src *) Lst_DeQueue (srcs);
  1010.  
  1011.     if (DEBUG(SUFF)) {
  1012.         printf ("\ttrying %s...", s->file);
  1013.     }
  1014.     /*
  1015.      * A file is considered to exist if either a node exists in the
  1016.      * graph for it or the file actually exists.
  1017.      */
  1018.     if ((Targ_FindNode(s->file, TARG_NOCREATE) != NILGNODE) ||
  1019.         (Dir_FindFile (s->file, s->suff->searchPath) != (char *) NULL))
  1020.     {
  1021.         if (DEBUG(SUFF)) {
  1022.         printf ("got it\n");
  1023.         }
  1024.         rs = s;
  1025.         break;
  1026.     } else {
  1027.         if (DEBUG(SUFF)) {
  1028.         printf ("not there\n");
  1029.         }
  1030.         SuffAddLevel (srcs, s);
  1031.     }
  1032.     }
  1033.     return (rs);
  1034. }
  1035.  
  1036. /*-
  1037.  *-----------------------------------------------------------------------
  1038.  * SuffFindCmds --
  1039.  *    See if any of the children of the target in the Src structure is
  1040.  *    one from which the target can be transformed. If there is one,
  1041.  *    a Src structure is put together for it and returned.
  1042.  *
  1043.  * Results:
  1044.  *    The Src structure of the "winning" child, or NIL if no such beast.
  1045.  *
  1046.  * Side Effects:
  1047.  *    A Src structure may be allocated.
  1048.  *
  1049.  *-----------------------------------------------------------------------
  1050.  */
  1051. static Src *
  1052. SuffFindCmds (targ)
  1053.     Src                  *targ;    /* Src structure to play with */
  1054. {
  1055.     LstNode           ln;     /* General-purpose list node */
  1056.     register GNode    *t,     /* Target GNode */
  1057.                   *s;     /* Source GNode */
  1058.     int                  prefLen;/* The length of the defined prefix */
  1059.     Suff              *suff;    /* Suffix on matching beastie */
  1060.     Src                  *ret;    /* Return value */
  1061.     char              *cp;
  1062.  
  1063.     t = targ->node;
  1064.     (void) Lst_Open (t->children);
  1065.     prefLen = strlen (targ->pref);
  1066.  
  1067.     while ((ln = Lst_Next (t->children)) != NILLNODE) {
  1068.     s = (GNode *)Lst_Datum (ln);
  1069.  
  1070.     cp = rindex (s->name, '/');
  1071.     if (cp == (char *)NULL) {
  1072.         cp = s->name;
  1073.     } else {
  1074.         cp++;
  1075.     }
  1076.     if (strncmp (cp, targ->pref, prefLen) == 0) {
  1077.         /*
  1078.          * The node matches the prefix ok, see if it has a known
  1079.          * suffix.
  1080.          */
  1081.         ln = Lst_Find (sufflist, (ClientData)&cp[prefLen],
  1082.                SuffSuffHasNameP);
  1083.         if (ln != NILLNODE) {
  1084.         /*
  1085.          * It even has a known suffix, see if there's a transformation
  1086.          * defined between the node's suffix and the target's suffix.
  1087.          *
  1088.          * XXX: Handle multi-stage transformations here, too.
  1089.          */
  1090.         suff = (Suff *)Lst_Datum (ln);
  1091.  
  1092.         if (Lst_Member (suff->parents,
  1093.                 (ClientData)targ->suff) != NILLNODE)
  1094.         {
  1095.             /*
  1096.              * Hot Damn! Create a new Src structure to describe
  1097.              * this transformation (making sure to duplicate the
  1098.              * source node's name so Suff_FindDeps can free it
  1099.              * again (ick)), and return the new structure.
  1100.              */
  1101.             ret = (Src *)emalloc (sizeof(Src));
  1102.             ret->file = strdup(s->name);
  1103.             ret->pref = targ->pref;
  1104.             ret->suff = suff;
  1105.             ret->parent = targ;
  1106.             ret->node = s;
  1107.             ret->children = 0;
  1108.             targ->children += 1;
  1109.             if (DEBUG(SUFF)) {
  1110.             printf ("\tusing existing source %s\n", s->name);
  1111.             }
  1112.             return (ret);
  1113.         }
  1114.         }
  1115.     }
  1116.     }
  1117.     Lst_Close (t->children);
  1118.     return ((Src *)NULL);
  1119. }
  1120.  
  1121. /*-
  1122.  *-----------------------------------------------------------------------
  1123.  * SuffExpandChildren --
  1124.  *    Expand the names of any children of a given node that contain
  1125.  *    variable invocations or file wildcards into actual targets.
  1126.  *
  1127.  * Results:
  1128.  *    === 0 (continue)
  1129.  *
  1130.  * Side Effects:
  1131.  *    The expanded node is removed from the parent's list of children,
  1132.  *    and the parent's unmade counter is decremented, but other nodes
  1133.  *     may be added.
  1134.  *
  1135.  *-----------------------------------------------------------------------
  1136.  */
  1137. static int
  1138. SuffExpandChildren(cgn, pgn)
  1139.     GNode       *cgn;        /* Child to examine */
  1140.     GNode       *pgn;        /* Parent node being processed */
  1141. {
  1142.     GNode    *gn;        /* New source 8) */
  1143.     LstNode       prevLN;    /* Node after which new source should be put */
  1144.     LstNode    ln;         /* List element for old source */
  1145.     char    *cp;        /* Expanded value */
  1146.  
  1147.     /*
  1148.      * New nodes effectively take the place of the child, so place them
  1149.      * after the child
  1150.      */
  1151.     prevLN = Lst_Member(pgn->children, (ClientData)cgn);
  1152.     
  1153.     /*
  1154.      * First do variable expansion -- this takes precedence over
  1155.      * wildcard expansion. If the result contains wildcards, they'll be gotten
  1156.      * to later since the resulting words are tacked on to the end of
  1157.      * the children list.
  1158.      */
  1159.     if (index(cgn->name, '$') != (char *)NULL) {
  1160.     if (DEBUG(SUFF)) {
  1161.         printf("Expanding \"%s\"...", cgn->name);
  1162.     }
  1163.     cp = Var_Subst(cgn->name, pgn, TRUE);
  1164.  
  1165.     if (cp != (char *)NULL) {
  1166.         Lst        members = Lst_Init(FALSE);
  1167.         
  1168.         if (cgn->type & OP_ARCHV) {
  1169.         /*
  1170.          * Node was an archive(member) target, so we want to call
  1171.          * on the Arch module to find the nodes for us, expanding
  1172.          * variables in the parent's context.
  1173.          */
  1174.         char    *sacrifice = cp;
  1175.  
  1176.         (void)Arch_ParseArchive(&sacrifice, members, pgn);
  1177.         } else {
  1178.         /*
  1179.          * Break the result into a vector of strings whose nodes
  1180.          * we can find, then add those nodes to the members list.
  1181.          * Unfortunately, we can't use brk_string b/c it
  1182.          * doesn't understand about variable specifications with
  1183.          * spaces in them...
  1184.          */
  1185.         char        *start;
  1186.         char        *initcp = cp;   /* For freeing... */
  1187.  
  1188.         for (start = cp; *start == ' ' || *start == '\t'; start++) {
  1189.             ;
  1190.         }
  1191.         for (cp = start; *cp != '\0'; cp++) {
  1192.             if (*cp == ' ' || *cp == '\t') {
  1193.             /*
  1194.              * White-space -- terminate element, find the node,
  1195.              * add it, skip any further spaces.
  1196.              */
  1197.             *cp++ = '\0';
  1198.             gn = Targ_FindNode(start, TARG_CREATE);
  1199.             (void)Lst_AtEnd(members, (ClientData)gn);
  1200.             while (*cp == ' ' || *cp == '\t') {
  1201.                 cp++;
  1202.             }
  1203.             /*
  1204.              * Adjust cp for increment at start of loop, but
  1205.              * set start to first non-space.
  1206.              */
  1207.             start = cp--;
  1208.             } else if (*cp == '$') {
  1209.             /*
  1210.              * Start of a variable spec -- contact variable module
  1211.              * to find the end so we can skip over it.
  1212.              */
  1213.             char    *junk;
  1214.             int     len;
  1215.             Boolean    doFree;
  1216.  
  1217.             junk = Var_Parse(cp, pgn, TRUE, &len, &doFree);
  1218.             if (junk != var_Error) {
  1219.                 cp += len - 1;
  1220.             }
  1221.  
  1222.             if (doFree) {
  1223.                 free(junk);
  1224.             }
  1225.             } else if (*cp == '\\' && *cp != '\0') {
  1226.             /*
  1227.              * Escaped something -- skip over it
  1228.              */
  1229.             cp++;
  1230.             }
  1231.         }
  1232.  
  1233.         if (cp != start) {
  1234.             /*
  1235.              * Stuff left over -- add it to the list too
  1236.              */
  1237.             gn = Targ_FindNode(start, TARG_CREATE);
  1238.             (void)Lst_AtEnd(members, (ClientData)gn);
  1239.         }
  1240.         /*
  1241.          * Point cp back at the beginning again so the variable value
  1242.          * can be freed.
  1243.          */
  1244.         cp = initcp;
  1245.         }
  1246.         /*
  1247.          * Add all elements of the members list to the parent node.
  1248.          */
  1249.         while(!Lst_IsEmpty(members)) {
  1250.         gn = (GNode *)Lst_DeQueue(members);
  1251.  
  1252.         if (DEBUG(SUFF)) {
  1253.             printf("%s...", gn->name);
  1254.         }
  1255.         if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) {
  1256.             (void)Lst_Append(pgn->children, prevLN, (ClientData)gn);
  1257.             prevLN = Lst_Succ(prevLN);
  1258.             (void)Lst_AtEnd(gn->parents, (ClientData)pgn);
  1259.             pgn->unmade++;
  1260.         }
  1261.         }
  1262.         Lst_Destroy(members, NOFREE);
  1263.         /*
  1264.          * Free the result
  1265.          */
  1266.         free((char *)cp);
  1267.     }
  1268.     /*
  1269.      * Now the source is expanded, remove it from the list of children to
  1270.      * keep it from being processed.
  1271.      */
  1272.     ln = Lst_Member(pgn->children, (ClientData)cgn);
  1273.     pgn->unmade--;
  1274.     Lst_Remove(pgn->children, ln);
  1275.     if (DEBUG(SUFF)) {
  1276.         printf("\n");
  1277.     }
  1278.     } else if (Dir_HasWildcards(cgn->name)) {
  1279.     Lst     exp;        /* List of expansions */
  1280.     Lst     path;        /* Search path along which to expand */
  1281.  
  1282.     /*
  1283.      * Find a path along which to expand the word.
  1284.      *
  1285.      * If the word has a known suffix, use that path.
  1286.      * If it has no known suffix and we're allowed to use the null
  1287.      *   suffix, use its path.
  1288.      * Else use the default system search path.
  1289.      */
  1290.     cp = cgn->name + strlen(cgn->name);
  1291.     ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffIsSuffixP);
  1292.  
  1293.     if (DEBUG(SUFF)) {
  1294.         printf("Wildcard expanding \"%s\"...", cgn->name);
  1295.     }
  1296.     
  1297.     if (ln != NILLNODE) {
  1298.         Suff    *s = (Suff *)Lst_Datum(ln);
  1299.  
  1300.         if (DEBUG(SUFF)) {
  1301.         printf("suffix is \"%s\"...", s->name);
  1302.         }
  1303.         path = s->searchPath;
  1304.     } else {
  1305.         /*
  1306.          * Use default search path
  1307.          */
  1308.         path = dirSearchPath;
  1309.     }
  1310.  
  1311.     /*
  1312.      * Expand the word along the chosen path
  1313.      */
  1314.     exp = Lst_Init(FALSE);
  1315.     Dir_Expand(cgn->name, path, exp);
  1316.  
  1317.     while (!Lst_IsEmpty(exp)) {
  1318.         /*
  1319.          * Fetch next expansion off the list and find its GNode
  1320.          */
  1321.         cp = (char *)Lst_DeQueue(exp);
  1322.  
  1323.         if (DEBUG(SUFF)) {
  1324.         printf("%s...", cp);
  1325.         }
  1326.         gn = Targ_FindNode(cp, TARG_CREATE);
  1327.  
  1328.         /*
  1329.          * If gn isn't already a child of the parent, make it so and
  1330.          * up the parent's count of unmade children.
  1331.          */
  1332.         if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) {
  1333.         (void)Lst_Append(pgn->children, prevLN, (ClientData)gn);
  1334.         prevLN = Lst_Succ(prevLN);
  1335.         (void)Lst_AtEnd(gn->parents, (ClientData)pgn);
  1336.         pgn->unmade++;
  1337.         }
  1338.     }
  1339.  
  1340.     /*
  1341.      * Nuke what's left of the list
  1342.      */
  1343.     Lst_Destroy(exp, NOFREE);
  1344.     
  1345.     /*
  1346.      * Now the source is expanded, remove it from the list of children to
  1347.      * keep it from being processed.
  1348.      */
  1349.     ln = Lst_Member(pgn->children, (ClientData)cgn);
  1350.     pgn->unmade--;
  1351.     Lst_Remove(pgn->children, ln);
  1352.     if (DEBUG(SUFF)) {
  1353.         printf("\n");
  1354.     }
  1355.     }
  1356.  
  1357.     return(0);
  1358. }
  1359.  
  1360. /*-
  1361.  *-----------------------------------------------------------------------
  1362.  * SuffApplyTransform --
  1363.  *    Apply a transformation rule, given the source and target nodes
  1364.  *    and suffixes.
  1365.  *
  1366.  * Results:
  1367.  *    TRUE if successful, FALSE if not.
  1368.  *
  1369.  * Side Effects:
  1370.  *    The source and target are linked and the commands from the
  1371.  *    transformation are added to the target node's commands list.
  1372.  *    All attributes but OP_DEPMASK and OP_TRANSFORM are applied
  1373.  *    to the target. The target also inherits all the sources for
  1374.  *    the transformation rule.
  1375.  *
  1376.  *-----------------------------------------------------------------------
  1377.  */
  1378. static Boolean
  1379. SuffApplyTransform(tGn, sGn, t, s)
  1380.     GNode       *tGn;        /* Target node */
  1381.     GNode       *sGn;        /* Source node */
  1382.     Suff        *t;         /* Target suffix */
  1383.     Suff        *s;         /* Source suffix */
  1384. {
  1385.     LstNode     ln;         /* General node */
  1386.     char        *tname;        /* Name of transformation rule */
  1387.     GNode       *gn;        /* Node for same */
  1388.  
  1389.     if (Lst_Member(tGn->children, (ClientData)sGn) == NILLNODE) {
  1390.     /*
  1391.      * Not already linked, so form the proper links between the
  1392.      * target and source.
  1393.      */
  1394.     (void)Lst_AtEnd(tGn->children, (ClientData)sGn);
  1395.     (void)Lst_AtEnd(sGn->parents, (ClientData)tGn);
  1396.     tGn->unmade += 1;
  1397.     }
  1398.  
  1399.     if ((sGn->type & OP_OPMASK) == OP_DOUBLEDEP) {
  1400.     /*
  1401.      * When a :: node is used as the implied source of a node, we have
  1402.      * to link all its cohorts in as sources as well. Only the initial
  1403.      * sGn gets the target in its iParents list, however, as that
  1404.      * will be sufficient to get the .IMPSRC variable set for tGn
  1405.      */
  1406.     for (ln=Lst_First(sGn->cohorts); ln != NILLNODE; ln=Lst_Succ(ln)) {
  1407.         gn = (GNode *)Lst_Datum(ln);
  1408.  
  1409.         if (Lst_Member(tGn->children, (ClientData)gn) == NILLNODE) {
  1410.         /*
  1411.          * Not already linked, so form the proper links between the
  1412.          * target and source.
  1413.          */
  1414.         (void)Lst_AtEnd(tGn->children, (ClientData)gn);
  1415.         (void)Lst_AtEnd(gn->parents, (ClientData)tGn);
  1416.         tGn->unmade += 1;
  1417.         }
  1418.     }
  1419.     }
  1420.     /*
  1421.      * Locate the transformation rule itself
  1422.      */
  1423.     tname = str_concat(s->name, t->name, 0);
  1424.     ln = Lst_Find(transforms, (ClientData)tname, SuffGNHasNameP);
  1425.     free(tname);
  1426.  
  1427.     if (ln == NILLNODE) {
  1428.     /*
  1429.      * Not really such a transformation rule (can happen when we're
  1430.      * called to link an OP_MEMBER and OP_ARCHV node), so return
  1431.      * FALSE.
  1432.      */
  1433.     return(FALSE);
  1434.     }
  1435.  
  1436.     gn = (GNode *)Lst_Datum(ln);
  1437.     
  1438.     if (DEBUG(SUFF)) {
  1439.     printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name);
  1440.     }
  1441.  
  1442.     /*
  1443.      * Record last child for expansion purposes
  1444.      */
  1445.     ln = Lst_Last(tGn->children);
  1446.     
  1447.     /*
  1448.      * Pass the buck to Make_HandleUse to apply the rule
  1449.      */
  1450.     (void)Make_HandleUse(gn, tGn);
  1451.  
  1452.     /*
  1453.      * Deal with wildcards and variables in any acquired sources
  1454.      */
  1455.     ln = Lst_Succ(ln);
  1456.     if (ln != NILLNODE) {
  1457.     Lst_ForEachFrom(tGn->children, ln,
  1458.             SuffExpandChildren, (ClientData)tGn);
  1459.     }
  1460.  
  1461.     /*
  1462.      * Keep track of another parent to which this beast is transformed so
  1463.      * the .IMPSRC variable can be set correctly for the parent.
  1464.      */
  1465.     (void)Lst_AtEnd(sGn->iParents, (ClientData)tGn);
  1466.  
  1467.     return(TRUE);
  1468. }
  1469.  
  1470.  
  1471. /*-
  1472.  *-----------------------------------------------------------------------
  1473.  * SuffFindArchiveDeps --
  1474.  *    Locate dependencies for an OP_ARCHV node.
  1475.  *
  1476.  * Results:
  1477.  *    None
  1478.  *
  1479.  * Side Effects:
  1480.  *    Same as Suff_FindDeps
  1481.  *
  1482.  *-----------------------------------------------------------------------
  1483.  */
  1484. static void
  1485. SuffFindArchiveDeps(gn)
  1486.     GNode       *gn;        /* Node for which to locate dependencies */
  1487. {
  1488.     char        *eoarch;    /* End of archive portion */
  1489.     char        *eoname;    /* End of member portion */
  1490.     GNode       *mem;        /* Node for member */
  1491.     static char    *copy[] = { /* Variables to be copied from the member node */
  1492.     TARGET,                /* Must be first */
  1493.     PREFIX,                /* Must be second */
  1494.     };
  1495.     char      *vals[sizeof(copy)/sizeof(copy[0])];
  1496.     int            i;          /* Index into copy and vals */
  1497.     char        *cp;        /* Suffix for member */
  1498.     Suff        *ms;        /* Suffix descriptor for member */
  1499.     char        *name;        /* Start of member's name */
  1500.     
  1501.     /*
  1502.      * The node is an archive(member) pair. so we must find a
  1503.      * suffix for both of them.
  1504.      */
  1505.     eoarch = index (gn->name, '(');
  1506.     eoname = index (eoarch, ')');
  1507.  
  1508.     *eoname = '\0';      /* Nuke parentheses during suffix search */
  1509.     *eoarch = '\0';      /* So a suffix can be found */
  1510.  
  1511.     name = eoarch + 1;
  1512.     
  1513.     /*
  1514.      * To simplify things, call Suff_FindDeps recursively on the member now,
  1515.      * so we can simply compare the member's .PREFIX and .TARGET variables
  1516.      * to locate its suffix. This allows us to figure out the suffix to
  1517.      * use for the archive without having to do a quadratic search over the
  1518.      * suffix list, backtracking for each one...
  1519.      */
  1520.     mem = Targ_FindNode(name, TARG_CREATE);
  1521.     Suff_FindDeps(mem);
  1522.  
  1523.     /*
  1524.      * Create the link between the two nodes right off
  1525.      */
  1526.     if (Lst_Member(gn->children, (ClientData)mem) == NILLNODE) {
  1527.     (void)Lst_AtEnd(gn->children, (ClientData)mem);
  1528.     (void)Lst_AtEnd(mem->parents, (ClientData)gn);
  1529.     gn->unmade += 1;
  1530.     }
  1531.     
  1532.     /*
  1533.      * Copy in the variables from the member node to this one.
  1534.      */
  1535.     for (i = (sizeof(copy)/sizeof(copy[0]))-1; i >= 0; i--) {
  1536.     vals[i] = Var_Value(copy[i], mem);
  1537.     Var_Set(copy[i], vals[i], gn);
  1538.     }
  1539.  
  1540.     ms = mem->suffix;
  1541.     if (ms == NULL) {
  1542.     /*
  1543.      * Didn't know what it was -- use .NULL suffix if not in make mode
  1544.      */
  1545.     if (DEBUG(SUFF)) {
  1546.         printf("using null suffix\n");
  1547.     }
  1548.     ms = suffNull;
  1549.     }
  1550.  
  1551.  
  1552.     /*
  1553.      * Set the other two local variables required for this target.
  1554.      */
  1555.     Var_Set (MEMBER, name, gn);
  1556.     Var_Set (ARCHIVE, gn->name, gn);
  1557.  
  1558.     if (ms != NULL) {
  1559.     /*
  1560.      * Member has a known suffix, so look for a transformation rule from
  1561.      * it to a possible suffix of the archive. Rather than searching
  1562.      * through the entire list, we just look at suffixes to which the
  1563.      * member's suffix may be transformed...
  1564.      */
  1565.     LstNode        ln;
  1566.  
  1567.     /*
  1568.      * Use first matching suffix...
  1569.      */
  1570.     ln = Lst_Find(ms->parents, eoarch, SuffSuffIsSuffixP);
  1571.  
  1572.     if (ln != NILLNODE) {
  1573.         /*
  1574.          * Got one -- apply it
  1575.          */
  1576.         if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) &&
  1577.         DEBUG(SUFF))
  1578.         {
  1579.         printf("\tNo transformation from %s -> %s\n",
  1580.                ms->name, ((Suff *)Lst_Datum(ln))->name);
  1581.         }
  1582.     }
  1583.     }
  1584.  
  1585.     /*
  1586.      * Replace the opening and closing parens now we've no need of the separate
  1587.      * pieces.
  1588.      */
  1589.     *eoarch = '('; *eoname = ')';
  1590.  
  1591.     /*
  1592.      * Pretend gn appeared to the left of a dependency operator so
  1593.      * the user needn't provide a transformation from the member to the
  1594.      * archive.
  1595.      */
  1596.     if (OP_NOP(gn->type)) {
  1597.     gn->type |= OP_DEPENDS;
  1598.     }
  1599.  
  1600.     /*
  1601.      * Flag the member as such so we remember to look in the archive for
  1602.      * its modification time.
  1603.      */
  1604.     mem->type |= OP_MEMBER;
  1605. }
  1606.  
  1607. /*-
  1608.  *-----------------------------------------------------------------------
  1609.  * SuffFindNormalDeps --
  1610.  *    Locate implicit dependencies for regular targets.
  1611.  *
  1612.  * Results:
  1613.  *    None.
  1614.  *
  1615.  * Side Effects:
  1616.  *    Same as Suff_FindDeps...
  1617.  *
  1618.  *-----------------------------------------------------------------------
  1619.  */
  1620. static void
  1621. SuffFindNormalDeps(gn)
  1622.     GNode       *gn;        /* Node for which to find sources */
  1623. {
  1624.     char        *eoname;    /* End of name */
  1625.     char        *sopref;    /* Start of prefix */
  1626.     Suff        *s;         /* Current suffix */
  1627.     LstNode     ln;         /* Next suffix node to check */
  1628.     Lst            srcs;        /* List of sources at which to look */
  1629.     Lst            targs;        /* List of targets to which things can be
  1630.                  * transformed. They all have the same file,
  1631.                  * but different suff and pref fields */
  1632.     Src            *bottom;    /* Start of found transformation path */
  1633.     Src     *src;        /* General Src pointer */
  1634.     char        *pref;        /* Prefix to use */
  1635.     Src            *targ;        /* General Src target pointer */
  1636.  
  1637.  
  1638.     eoname = gn->name + strlen(gn->name);
  1639.  
  1640.     sopref = gn->name;
  1641.     
  1642.     /*
  1643.      * Begin at the beginning...
  1644.      */
  1645.     ln = Lst_First(sufflist);
  1646.     srcs = Lst_Init(FALSE);
  1647.     targs = Lst_Init(FALSE);
  1648.  
  1649.     /*
  1650.      * We're caught in a catch-22 here. On the one hand, we want to use any
  1651.      * transformation implied by the target's sources, but we can't examine
  1652.      * the sources until we've expanded any variables/wildcards they may hold,
  1653.      * and we can't do that until we've set up the target's local variables
  1654.      * and we can't do that until we know what the proper suffix for the
  1655.      * target is (in case there are two suffixes one of which is a suffix of
  1656.      * the other) and we can't know that until we've found its implied
  1657.      * source, which we may not want to use if there's an existing source
  1658.      * that implies a different transformation.
  1659.      *
  1660.      * In an attempt to get around this, which may not work all the time,
  1661.      * but should work most of the time, we look for implied sources first,
  1662.      * checking transformations to all possible suffixes of the target,
  1663.      * use what we find to set the target's local variables, expand the
  1664.      * children, then look for any overriding transformations they imply.
  1665.      * Should we find one, we discard the one we found before.
  1666.      */
  1667.     while(ln != NILLNODE) {
  1668.     /*
  1669.      * Look for next possible suffix...
  1670.      */
  1671.     ln = Lst_FindFrom(sufflist, ln, eoname, SuffSuffIsSuffixP);
  1672.  
  1673.     if (ln != NILLNODE) {
  1674.         int        prefLen;        /* Length of the prefix */
  1675.         Src        *targ;
  1676.         
  1677.         /*
  1678.          * Allocate a Src structure to which things can be transformed
  1679.          */
  1680.         targ = (Src *)emalloc(sizeof(Src));
  1681.         targ->file = strdup(gn->name);
  1682.         targ->suff = (Suff *)Lst_Datum(ln);
  1683.         targ->node = gn;
  1684.         targ->parent = (Src *)NULL;
  1685.         
  1686.         /*
  1687.          * Allocate room for the prefix, whose end is found by subtracting
  1688.          * the length of the suffix from the end of the name.
  1689.          */
  1690.         prefLen = (eoname - targ->suff->nameLen) - sopref;
  1691.         targ->pref = emalloc(prefLen + 1);
  1692.         bcopy(sopref, targ->pref, prefLen);
  1693.         targ->pref[prefLen] = '\0';
  1694.  
  1695.         /*
  1696.          * Add nodes from which the target can be made
  1697.          */
  1698.         SuffAddLevel(srcs, targ);
  1699.  
  1700.         /*
  1701.          * Record the target so we can nuke it
  1702.          */
  1703.         (void)Lst_AtEnd(targs, (ClientData)targ);
  1704.  
  1705.         /*
  1706.          * Search from this suffix's successor...
  1707.          */
  1708.         ln = Lst_Succ(ln);
  1709.     }
  1710.     }
  1711.  
  1712.     /*
  1713.      * Handle target of unknown suffix...
  1714.      */
  1715.     if (Lst_IsEmpty(targs) && suffNull != NULL) {
  1716.     if (DEBUG(SUFF)) {
  1717.         printf("\tNo known suffix on %s. Using .NULL suffix\n", gn->name);
  1718.     }
  1719.     
  1720.     targ = (Src *)emalloc(sizeof(Src));
  1721.     targ->file = strdup(gn->name);
  1722.     targ->suff = suffNull;
  1723.     targ->node = gn;
  1724.     targ->parent = (Src *)NULL;
  1725.     targ->pref = strdup(sopref);
  1726.  
  1727.     SuffAddLevel(srcs, targ);
  1728.     (void)Lst_AtEnd(targs, (ClientData)targ);
  1729.     }
  1730.     
  1731.     /*
  1732.      * Using the list of possible sources built up from the target suffix(es),
  1733.      * try and find an existing file/target that matches.
  1734.      */
  1735.     bottom = SuffFindThem(srcs);
  1736.  
  1737.     if (bottom == (Src *)NULL) {
  1738.     /*
  1739.      * No known transformations -- use the first suffix found for setting
  1740.      * the local variables.
  1741.      */
  1742.     if (!Lst_IsEmpty(targs)) {
  1743.         targ = (Src *)Lst_Datum(Lst_First(targs));
  1744.     } else {
  1745.         targ = (Src *)NULL;
  1746.     }
  1747.     } else {
  1748.     /*
  1749.      * Work up the transformation path to find the suffix of the
  1750.      * target to which the transformation was made.
  1751.      */
  1752.     for (targ = bottom; targ->parent != NULL; targ = targ->parent) {
  1753.         ;
  1754.     }
  1755.     }
  1756.  
  1757.     /*
  1758.      * The .TARGET variable we always set to be the name at this point,
  1759.      * since it's only set to the path if the thing is only a source and
  1760.      * if it's only a source, it doesn't matter what we put here as far
  1761.      * as expanding sources is concerned, since it has none...
  1762.      */
  1763.     Var_Set(TARGET, gn->name, gn);
  1764.  
  1765.     pref = (targ != NULL) ? targ->pref : gn->name;
  1766.     Var_Set(PREFIX, pref, gn);
  1767.  
  1768.     /*
  1769.      * Now we've got the important local variables set, expand any sources
  1770.      * that still contain variables or wildcards in their names.
  1771.      */
  1772.     Lst_ForEach(gn->children, SuffExpandChildren, (ClientData)gn);
  1773.     
  1774.     if (targ == NULL) {
  1775.     if (DEBUG(SUFF)) {
  1776.         printf("\tNo valid suffix on %s\n", gn->name);
  1777.     }
  1778.  
  1779. sfnd_abort:
  1780.     /*
  1781.      * Deal with finding the thing on the default search path if the
  1782.      * node is only a source (not on the lhs of a dependency operator
  1783.      * or [XXX] it has neither children or commands).
  1784.      */
  1785.     if (OP_NOP(gn->type) ||
  1786.         (Lst_IsEmpty(gn->children) && Lst_IsEmpty(gn->commands)))
  1787.     {
  1788.         gn->path = Dir_FindFile(gn->name,
  1789.                     (targ == NULL ? dirSearchPath :
  1790.                      targ->suff->searchPath));
  1791.         if (gn->path != NULL) {
  1792.         Var_Set(TARGET, gn->path, gn);
  1793.  
  1794.         if (targ != NULL) {
  1795.             /*
  1796.              * Suffix known for the thing -- trim the suffix off
  1797.              * the path to form the proper .PREFIX variable.
  1798.              */
  1799.             int        len = strlen(gn->path);
  1800.             char    savec;
  1801.  
  1802.             gn->suffix = targ->suff;
  1803.  
  1804.             savec = gn->path[len-targ->suff->nameLen];
  1805.             gn->path[len-targ->suff->nameLen] = '\0';
  1806.  
  1807.             Var_Set(PREFIX, gn->path, gn);
  1808.  
  1809.             gn->path[len-targ->suff->nameLen] = savec;
  1810.         } else {
  1811.             /*
  1812.              * The .PREFIX gets the full path if the target has
  1813.              * no known suffix.
  1814.              */
  1815.             gn->suffix = NULL;
  1816.  
  1817.             Var_Set(PREFIX, gn->path, gn);
  1818.         }
  1819.         }
  1820.     } else {
  1821.         /*
  1822.          * Not appropriate to search for the thing -- set the
  1823.          * path to be the name so Dir_MTime won't go grovelling for
  1824.          * it.
  1825.          */
  1826.         gn->suffix = (targ == NULL) ? NULL : targ->suff;
  1827.         gn->path = gn->name;
  1828.     }
  1829.     
  1830.     goto sfnd_return;
  1831.     }
  1832.  
  1833.     /*
  1834.      * If the suffix indicates that the target is a library, mark that in
  1835.      * the node's type field.
  1836.      */
  1837.     if (targ->suff->flags & SUFF_LIBRARY) {
  1838.     gn->type |= OP_LIB;
  1839.     }
  1840.  
  1841.     /*
  1842.      * Check for overriding transformation rule implied by sources
  1843.      */
  1844.     if (!Lst_IsEmpty(gn->children)) {
  1845.     src = SuffFindCmds(targ);
  1846.  
  1847.     if (src != (Src *)NULL) {
  1848.         /*
  1849.          * Free up all the Src structures in the transformation path
  1850.          * up to, but not including, the parent node.
  1851.          */
  1852.         while (bottom && bottom->parent != NULL) {
  1853.         Src *p = bottom->parent;
  1854.  
  1855.         SuffFreeSrc(bottom);
  1856.         bottom = p;
  1857.         }
  1858.         bottom = src;
  1859.     }
  1860.     }
  1861.  
  1862.     if (bottom == NULL) {
  1863.     /*
  1864.      * No idea from where it can come -- return now.
  1865.      */
  1866.     goto sfnd_abort;
  1867.     }
  1868.  
  1869.     /*
  1870.      * We now have a list of Src structures headed by 'bottom' and linked via
  1871.      * their 'parent' pointers. What we do next is create links between
  1872.      * source and target nodes (which may or may not have been created)
  1873.      * and set the necessary local variables in each target. The
  1874.      * commands for each target are set from the commands of the
  1875.      * transformation rule used to get from the src suffix to the targ
  1876.      * suffix. Note that this causes the commands list of the original
  1877.      * node, gn, to be replaced by the commands of the final
  1878.      * transformation rule. Also, the unmade field of gn is incremented.
  1879.      * Etc. 
  1880.      */
  1881.     if (bottom->node == NILGNODE) {
  1882.     bottom->node = Targ_FindNode(bottom->file, TARG_CREATE);
  1883.     }
  1884.     
  1885.     for (src = bottom; src->parent != (Src *)NULL; src = src->parent) {
  1886.     targ = src->parent;
  1887.  
  1888.     src->node->suffix = src->suff;
  1889.  
  1890.     if (targ->node == NILGNODE) {
  1891.         targ->node = Targ_FindNode(targ->file, TARG_CREATE);
  1892.     }
  1893.  
  1894.     SuffApplyTransform(targ->node, src->node,
  1895.                targ->suff, src->suff);
  1896.  
  1897.     if (targ->node != gn) {
  1898.         /*
  1899.          * Finish off the dependency-search process for any nodes
  1900.          * between bottom and gn (no point in questing around the
  1901.          * filesystem for their implicit source when it's already
  1902.          * known). Note that the node can't have any sources that
  1903.          * need expanding, since SuffFindThem will stop on an existing
  1904.          * node, so all we need to do is set the standard and System V
  1905.          * variables.
  1906.          */
  1907.         targ->node->type |= OP_DEPS_FOUND;
  1908.  
  1909.         Var_Set(PREFIX, targ->pref, targ->node);
  1910.     
  1911.         Var_Set(TARGET, targ->node->name, targ->node);
  1912.     }
  1913.     }
  1914.  
  1915.     gn->suffix = src->suff;
  1916.  
  1917.     /*
  1918.      * So Dir_MTime doesn't go questing for it...
  1919.      */
  1920.     gn->path = gn->name;
  1921.  
  1922.     /*
  1923.      * Nuke the transformation path and the Src structures left over in the
  1924.      * two lists.
  1925.      */
  1926.     SuffFreeSrc(bottom);
  1927.  
  1928. sfnd_return:
  1929.     Lst_Destroy(srcs, SuffFreeSrc);
  1930.     Lst_Destroy(targs, SuffFreeSrc);
  1931.  
  1932. }
  1933.     
  1934.     
  1935.  
  1936.  
  1937. /*-
  1938.  *-----------------------------------------------------------------------
  1939.  * Suff_FindDeps  --
  1940.  *    Find implicit sources for the target described by the graph node
  1941.  *    gn
  1942.  *
  1943.  * Results:
  1944.  *    Nothing.
  1945.  *
  1946.  * Side Effects:
  1947.  *    Nodes are added to the graph below the passed-in node. The nodes
  1948.  *    are marked to have their IMPSRC variable filled in. The
  1949.  *    PREFIX variable is set for the given node and all its
  1950.  *    implied children.
  1951.  *
  1952.  * Notes:
  1953.  *    The path found by this target is the shortest path in the
  1954.  *    transformation graph, which may pass through non-existent targets,
  1955.  *    to an existing target. The search continues on all paths from the
  1956.  *    root suffix until a file is found. I.e. if there's a path
  1957.  *    .o -> .c -> .l -> .l,v from the root and the .l,v file exists but
  1958.  *    the .c and .l files don't, the search will branch out in
  1959.  *    all directions from .o and again from all the nodes on the
  1960.  *    next level until the .l,v node is encountered.
  1961.  *
  1962.  *-----------------------------------------------------------------------
  1963.  */
  1964. void
  1965. Suff_FindDeps (gn)
  1966.     GNode         *gn;              /* node we're dealing with */
  1967. {
  1968.     if (gn->type & OP_DEPS_FOUND) {
  1969.     /*
  1970.      * If dependencies already found, no need to do it again...
  1971.      */
  1972.     return;
  1973.     } else {
  1974.     gn->type |= OP_DEPS_FOUND;
  1975.     }
  1976.     
  1977.     if (DEBUG(SUFF)) {
  1978.     printf ("Suff_FindDeps (%s)\n", gn->name);
  1979.     }
  1980.     
  1981.     if (gn->type & OP_ARCHV) {
  1982.     SuffFindArchiveDeps(gn);
  1983.     } else if (gn->type & OP_LIB) {
  1984.     /*
  1985.      * If the node is a library, it is the arch module's job to find it
  1986.      * and set the TARGET variable accordingly. We merely provide the
  1987.      * search path, assuming all libraries end in ".a" (if the suffix
  1988.      * hasn't been defined, there's nothing we can do for it, so we just
  1989.      * set the TARGET variable to the node's name in order to give it a
  1990.      * value).
  1991.      */
  1992.     LstNode    ln;
  1993.     Suff    *s;
  1994.     
  1995.     ln = Lst_Find (sufflist, (ClientData)LIBSUFF, SuffSuffHasNameP);
  1996.     if (ln != NILLNODE) {
  1997.         gn->suffix = s = (Suff *) Lst_Datum (ln);
  1998.         Arch_FindLib (gn, s->searchPath);
  1999.     } else {
  2000.         gn->suffix = NULL;
  2001.         Var_Set (TARGET, gn->name, gn);
  2002.     }
  2003.     /*
  2004.      * Because a library (-lfoo) target doesn't follow the standard
  2005.      * filesystem conventions, we don't set the regular variables for
  2006.      * the thing. .PREFIX is simply made empty...
  2007.      */
  2008.     Var_Set(PREFIX, "", gn);
  2009.     } else {
  2010.     SuffFindNormalDeps(gn);
  2011.     }
  2012. }
  2013.  
  2014. /*-
  2015.  *-----------------------------------------------------------------------
  2016.  * Suff_SetNull --
  2017.  *    Define which suffix is the null suffix.
  2018.  *
  2019.  * Results:
  2020.  *    None.
  2021.  *
  2022.  * Side Effects:
  2023.  *    'suffNull' is altered.
  2024.  *
  2025.  * Notes:
  2026.  *    Need to handle the changing of the null suffix gracefully so the
  2027.  *    old transformation rules don't just go away.
  2028.  *
  2029.  *-----------------------------------------------------------------------
  2030.  */
  2031. void
  2032. Suff_SetNull(name)
  2033.     char    *name;        /* Name of null suffix */
  2034. {
  2035.     Suff    *s;
  2036.     LstNode ln;
  2037.  
  2038.     ln = Lst_Find(sufflist, (ClientData)name, SuffSuffHasNameP);
  2039.     if (ln != NILLNODE) {
  2040.     s = (Suff *)Lst_Datum(ln);
  2041.     if (suffNull != (Suff *)NULL) {
  2042.         suffNull->flags &= ~SUFF_NULL;
  2043.     }
  2044.     s->flags |= SUFF_NULL;
  2045.     /*
  2046.      * XXX: Here's where the transformation mangling would take place
  2047.      */
  2048.     suffNull = s;
  2049.     } else {
  2050.     Parse_Error (PARSE_WARNING, "Desired null suffix %s not defined.",
  2051.              name);
  2052.     }
  2053. }
  2054.  
  2055. /*-
  2056.  *-----------------------------------------------------------------------
  2057.  * Suff_Init --
  2058.  *    Initialize suffixes module
  2059.  *
  2060.  * Results:
  2061.  *    None
  2062.  *
  2063.  * Side Effects:
  2064.  *    Many
  2065.  *-----------------------------------------------------------------------
  2066.  */
  2067. void
  2068. Suff_Init ()
  2069. {
  2070.     sufflist = Lst_Init (FALSE);
  2071.     transforms = Lst_Init (FALSE);
  2072.  
  2073.     sNum = 0;
  2074.     /*
  2075.      * Create null suffix for single-suffix rules (POSIX). The thing doesn't
  2076.      * actually go on the suffix list or everyone will think that's its
  2077.      * suffix.
  2078.      */
  2079.     emptySuff = suffNull = (Suff *) emalloc (sizeof (Suff));
  2080.  
  2081.     suffNull->name =           strdup ("");
  2082.     suffNull->nameLen =     0;
  2083.     suffNull->searchPath =  Lst_Init (FALSE);
  2084.     suffNull->children =    Lst_Init (FALSE);
  2085.     suffNull->parents =        Lst_Init (FALSE);
  2086.     suffNull->sNum =           sNum++;
  2087.     suffNull->flags =          SUFF_NULL;
  2088.  
  2089. }
  2090.  
  2091. /********************* DEBUGGING FUNCTIONS **********************/
  2092.  
  2093. static int SuffPrintName(s) Suff *s; {printf ("%s ", s->name); return (0);}
  2094.  
  2095. static int
  2096. SuffPrintSuff (s)
  2097.     Suff    *s;
  2098. {
  2099.     int        flags;
  2100.     int        flag;
  2101.  
  2102.     printf ("# `%s'", s->name);
  2103.     
  2104.     flags = s->flags;
  2105.     if (flags) {
  2106.     fputs (" (", stdout);
  2107.     while (flags) {
  2108.         flag = 1 << (ffs(flags) - 1);
  2109.         flags &= ~flag;
  2110.         switch (flag) {
  2111.         case SUFF_NULL:
  2112.             printf ("NULL");
  2113.             break;
  2114.         case SUFF_INCLUDE:
  2115.             printf ("INCLUDE");
  2116.             break;
  2117.         case SUFF_LIBRARY:
  2118.             printf ("LIBRARY");
  2119.             break;
  2120.         }
  2121.         putc(flags ? '|' : ')', stdout);
  2122.     }
  2123.     }
  2124.     putc ('\n', stdout);
  2125.     printf ("#\tTo: ");
  2126.     Lst_ForEach (s->parents, SuffPrintName, (ClientData)0);
  2127.     putc ('\n', stdout);
  2128.     printf ("#\tFrom: ");
  2129.     Lst_ForEach (s->children, SuffPrintName, (ClientData)0);
  2130.     putc ('\n', stdout);
  2131.     printf ("#\tSearch Path: ");
  2132.     Dir_PrintPath (s->searchPath);
  2133.     putc ('\n', stdout);
  2134.     return (0);
  2135. }
  2136.  
  2137. static int
  2138. SuffPrintTrans (t)
  2139.     GNode   *t;
  2140. {
  2141.     extern int Targ_PrintCmd();
  2142.  
  2143.     printf ("%-16s: ", t->name);
  2144.     Targ_PrintType (t->type);
  2145.     putc ('\n', stdout);
  2146.     Lst_ForEach (t->commands, Targ_PrintCmd, (ClientData)0);
  2147.     putc ('\n', stdout);
  2148.     return(0);
  2149. }
  2150.  
  2151. Suff_PrintAll()
  2152. {
  2153.     printf ("#*** Suffixes:\n");
  2154.     Lst_ForEach (sufflist, SuffPrintSuff, (ClientData)0);
  2155.  
  2156.     printf ("#*** Transformations:\n");
  2157.     Lst_ForEach (transforms, SuffPrintTrans, (ClientData)0);
  2158. }
  2159.  
  2160.